Skip to content

fix(gates): witness the ingest so truncated checkouts cannot pass silently - #178

Merged
emrecdr merged 1 commit into
mainfrom
fix/gate-ingest-witness
Jul 29, 2026
Merged

fix(gates): witness the ingest so truncated checkouts cannot pass silently#178
emrecdr merged 1 commit into
mainfrom
fix/gate-ingest-witness

Conversation

@emrecdr

@emrecdr emrecdr commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

Three validated gate-integrity findings from the cycle-3 audit, fixed as one class — a truncated checkout must never convert configured gates into silent no-ops:

  • The ingest witness. A shallow merge-tip checkout (the actions/checkout default on PR merge refs, under default merge filtering) ingests zero commits, and every gate then passed green with result=pass. Now: zero persisted commits + a real HEAD = hard error (exit 3, message naming fetch-depth), on both codelore check and MCP check_gates. The witness gates on the persisted store count rather than in-memory ingest stats — a zero-commit run poisons the cache, and later cache-hits have no fresh stats; the store count is the same quantity, readable on hit and miss. A .git/shallow preflight warns loudly. The degraded sentinel — whose old conjunction derived both sides from the same join and was structurally blind to ingest-level failure — gains an independent witness (HEAD-tree scorable-source count, computed only on the empty-health path; the commit-count case is preempted upstream, and a legitimately source-less repo stays a valid vacuous pass).
  • Structured skip disclosure. MCP check_gates's skipped_gates is now {gate, reason} (one unified shape — the existing structural skips gained reasons too), and the [new_code] runtime skip reports through it: an agent can finally distinguish "passed" from "did not run". Both CLI and MCP wordings discriminate a shallow checkout (naming fetch-depth) from a genuinely young repository.
  • Ratchet integrity. .codelore-ratchet.toml — a committed file — was written non-atomically, and a torn 0-byte file parsed cleanly into "everything improved" + silent team-wide rebaseline. Writes now route through the shared atomic_publish; present-but-empty content is rejected as corrupt with a restore-or-delete error. Absent / no-floors-configured / destroyed are three distinct states.

Verification

  • lib 99 binaries / cli 44+99+28 pass (independently re-run); clippy all-features clean; fmt clean; self-gate PASS
  • Byte-discipline: healthy-repo check output unchanged (witness guards inert on a full clone; no [new_code] configured here; no ratchet file)

…ently

A shallow fetch-depth checkout whose tip is a merge commit ingests zero
history under the default merge filter, leaving every quality gate with
nothing to violate — `codelore check` printed PASS (0 files evaluated),
wrote result=pass, and exited 0. Three related gate-integrity holes are
closed as one class:

- Witness the ingest on both gate paths (`codelore check` and the
  check_gates MCP tool): a real HEAD over a zero-commit store is now a hard
  error (exit 3, the shallow/corrupted-repo bucket) that names fetch-depth,
  never a pass. A shallow checkout that did ingest partial history is warned
  about loudly, and the code_health_min degraded sentinel now witnesses
  "the repository has analyzable source" by reading the HEAD tree directly
  rather than counting complexity_metrics — which derives from the same
  changes-commits join as the health rows and so could not fire for the
  very ingest-blindness it guards. A source-less tree stays a vacuous pass.

- Disclose the [new_code] shallow-history skip as structured data on the
  check_gates MCP path (a {gate, reason} entry in skipped_gates, unified
  with the structural check-only skips, which gain reasons too) and make
  the reason discriminate a shallow checkout (names fetch-depth) from a
  genuinely young repository on both the CLI and MCP paths.

- Write .codelore-ratchet.toml atomically through the shared
  write-to-temp + fsync + rename helper, so an interrupted write can no
  longer leave a 0-byte file; and reject a present-but-empty ratchet file
  as corrupt instead of parsing it to an all-None snapshot and silently
  rebaselining the gate. No file (initialize), a well-formed empty table
  (no floors configured), and a destroyed file (loud error) are now
  distinct states.
@emrecdr
emrecdr merged commit d8e909a into main Jul 29, 2026
11 checks passed
@emrecdr
emrecdr deleted the fix/gate-ingest-witness branch July 29, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants